package rest

import (
	"net/http"
	"strconv"

	"bilinadmin/internal/object"

	"bilinadmin/internal/service"

	"github.com/labstack/echo/v4"
	"github.com/pkg/errors"

	"bilinadmin/internal/conf"
	"bilinadmin/pkg/log"
	"bilinadmin/pkg/lueerror"
	"bilinadmin/pkg/util"
)

type Base struct {
	logger log.Factory
	cfg    *conf.Config
}

var base *Base

// InitRestBase 初始化 rest base config
func InitRestBase(logger log.Factory, cfg *conf.Config) {
	base = &Base{
		logger: logger,
		cfg:    cfg,
	}
}

// ParseBody 请求 body 解析
func (b *Base) ParseBody(c echo.Context, model interface{}) lueerror.LueError {
	if err := c.Bind(model); err != nil {
		return lueerror.InvalidRequest(err)
	}
	if errV := c.Validate(model); errV != nil {
		return lueerror.InvalidRequest(errV)
	}
	return nil
}

type httpResp struct {
	Code    string      `json:"code"`
	Msg     string      `json:"msg"`
	Detail  string      `json:"detail"`
	Data    interface{} `json:"data"`
	Success bool        `json:"success"`
}

// SimpleRet simple http return
func (b *Base) SimpleRet(c echo.Context, ret interface{}, errL lueerror.LueError) error {
	if errL != nil {
		return errL
	}
	resp := &httpResp{
		Code:    "10000",
		Msg:     "",
		Detail:  "",
		Data:    ret,
		Success: true,
	}
	return c.JSON(http.StatusOK, resp)
}

// MobileCheck 手机号校验
func (b *Base) MobileCheck(mobile string) lueerror.LueError {
	if !util.CNMobile(mobile) {
		return lueerror.InvalidMobile(errors.New("手机号格式错误"))
	}
	return nil
}

// EmailCheck 邮箱校验
func (b *Base) EmailCheck(email string) lueerror.LueError {
	if !util.Email(email) {
		return lueerror.InvalidEmail(errors.New("邮箱格式错误"))
	}
	return nil
}

// GenBilinToken 生成token
func (b *Base) GenBilinToken(GID, Name string, brandId, empId int64) (string, lueerror.LueError) {
	return service.GetService().GenBilinToken(GID, Name, brandId, empId)
}

// VerifyBilinToken token 验证
func (b *Base) VerifyBilinToken(c echo.Context) (*service.BilinToken, lueerror.LueError) {
	token := c.Request().Header.Get("B-Token")
	if token == "" {
		return nil, lueerror.AuthGrantErr(errors.New("token 为空"))
	}
	return service.GetService().VerifyBilinToken(token)
}

// VerifyAccountToken token 验证
func (b *Base) VerifyAccountToken(c echo.Context) (*service.AccountToken, lueerror.LueError) {
	token := c.Request().Header.Get("G-Token")
	if token == "" {
		return nil, lueerror.AuthGrantErr(errors.New("token 为空"))
	}
	return service.GetService().VerifyAccountToken(token)
}

// VerifyAccountOrBilinToken 验证 B-Token 或 G-Token
func (b *Base) VerifyAccountOrBilinToken(c echo.Context) lueerror.LueError {
	token := c.Request().Header.Get("B-Token")
	if token != "" {
		_, errL := service.GetService().VerifyBilinToken(token)
		return errL
	}
	token = c.Request().Header.Get("G-Token")
	if token == "" {
		return lueerror.AuthGrantErr(errors.New("token 为空"))
	}
	_, errL := service.GetService().VerifyAccountToken(token)
	return errL
}

// PermissionCheck bilin 后台权限验证
func (b *Base) PermissionCheck(c echo.Context, permission string) (*service.BilinToken, lueerror.LueError) {
	token, errL := b.VerifyBilinToken(c)
	if errL != nil {
		return nil, errL
	}
	var storeId int64
	st := c.QueryParam("p_store_id")
	if st != "" {
		var err error
		storeId, err = strconv.ParseInt(st, 10, 64)
		if err != nil {
			return nil, lueerror.InvalidRequest(err)
		}
	}
	ctx := c.Request().Context()
	hasPerm, errL := service.GetRolePermissionSrv().PermissionVerify(ctx, token.BrandId, storeId, token.EmpId, permission)
	if errL != nil {
		return nil, errL
	}
	if !hasPerm {
		return nil, lueerror.Forbidden(errors.New("无权限操作"))
	}
	return token, nil
}

func parseEmpId(c echo.Context, isRequired bool) (int64, lueerror.LueError) {
	emp := c.QueryParam("emp_id")
	if emp == "" {
		if isRequired {
			return 0, lueerror.InvalidRequest(errors.New("员工id必填"))
		}
		return 0, nil
	}
	empId, err := strconv.ParseInt(emp, 10, 64)
	if err != nil {
		return 0, lueerror.InvalidRequest(err)
	}
	return empId, nil
}

func parseStoreId(c echo.Context, isRequired bool) (int64, lueerror.LueError) {
	st := c.QueryParam("p_store_id")
	if st == "" {
		if isRequired {
			return 0, lueerror.InvalidRequest(errors.New("门店id必填"))
		}
		return 0, nil
	}
	storeId, err := strconv.ParseInt(st, 10, 64)
	if err != nil {
		return 0, lueerror.InvalidRequest(err)
	}
	return storeId, nil
}

// 解析分页逻辑
func paginationParse(c echo.Context) *object.Pagination {
	pageNo := c.QueryParam("page_no")
	pageSize := c.QueryParam("page_size")
	pg := object.NewPagination(0, 0)
	pg.ParsePageNo(pageNo)
	pg.ParsePageSize(pageSize)
	return pg
}

// 解析 int64 query 参数
func parseInt64Query(c echo.Context, key string) (int64, lueerror.LueError) {
	val := c.QueryParam(key)
	if val == "" {
		return 0, nil
	}
	ret, err := strconv.ParseInt(val, 10, 64)
	if err != nil {
		return 0, lueerror.InvalidRequest(err)
	}
	return ret, nil
}
